package spectra.ee.web.qna.service;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import spectra.base.log.LP;
import spectra.base.log.Logger;
import spectra.base.sql.ibatis.SqlMapperWeb;
import spectra.base.util.Base64;
import spectra.base.util.DateUtil;
import spectra.base.util.StringUtil;
import spectra.ee.commons.common.model.Attach;
import spectra.ee.commons.qna.model.MailReceiver;
import spectra.ee.commons.qna.model.Qna;
import spectra.ee.commons.qna.model.QnaBoard;
import spectra.ee.commons.qna.model.QnaContents;
import spectra.ee.commons.qna.model.QnaProcess;
import spectra.ee.web.qna.model.QnaBoardView;

import com.ibatis.sqlmap.client.SqlMapClient;

/**
 * Qna 관련 클래스.
 *
 * @author shchae
 */
public class QnaServiceBase
{

    /** Logger객체. */
    private static Logger logger = Logger.getLoggerInstance(QnaServiceBase.class.getName());

    /** SqlMapClient 객체. */
    protected static SqlMapClient sqlMap = SqlMapperWeb.getSqlMapWebInstance();

    /**
    * <pre>
    * 공개게시판 리스트 개수를 가져오는 메소드.
    * 채널 조건이 없는 경우 사용하는 함수로, 전체 채널의 QnA 리스트 개수를 가져올때 사용한다.
    * </pre>.
    *
    * @param domainId 도메인ID.
    * @param customerId 고객ID.
    * @param searchNodeId 검색노드ID.
    * @param searchCondition 검색조건.
    * @param searchKeyword 검색키워드.
    *
    * @return 목록갯수.
    *
    * @throws Exception the exception
    */
    public int selectQnaListCount(String domainId, String customerId, String searchNodeId, String searchCondition, String searchKeyword) throws Exception
    {
    	String channelId = null;
    	return selectQnaListCount(domainId, customerId, channelId, searchNodeId, searchCondition, searchKeyword);
    }
    /**
     * <pre>
     * 공개게시판 리스트 개수를 가져오는 메소드
     * </pre>.
     *
     * @param domainId 도메인ID.
     * @param customerId 고객ID.
     * @paran channelId 채널ID.
     * @param searchNodeId 검색노드ID.
     * @param searchCondition 검색조건.
     * @param searchKeyword 검색키워드.
     *
     * @return 목록갯수.
     *
     * @throws Exception the exception
     */
    public int selectQnaListCount(String domainId, String customerId, String channelId, String searchNodeId, String searchCondition, String searchKeyword) throws Exception
    {
    	searchKeyword = searchKeyword.replaceAll("%", "\\\\%");
        searchKeyword = searchKeyword.replaceAll(",", "\\\\,");
        searchKeyword = searchKeyword.replaceAll("_", "\\\\_");
        searchKeyword = "%"+searchKeyword+"%";

        QnaBoardView obj = new QnaBoardView();
        obj.setQnaDomainId(domainId);
        obj.setCustomerId(customerId);
        obj.setSearchNodeId(searchNodeId);
        obj.setSearchKeyword(searchKeyword);
        obj.setSearchCondition(searchCondition);
        obj.setChannelId(channelId);
        return ((Integer) sqlMap.queryForObject("Qna.selectQnaListCount", obj)).intValue();
    }

    /**
    * <pre>
    * 공개게시판 리스트를 가져오는 메소드.
    * channelId 조건이 없는 경우로 모든 채널의 QnA 목록을 가져온다.
    * </pre>.
    *
    * @param domainId 도메인ID.
    * @param customerId 고객ID.
    * @param ipageNo 페이지번호.
    * @param rowsPerPage 한페이지 나오는 글 개수.
    * @param orderBy 정렬.
    * @param searchNodeId 검색노드ID.
    * @param searchCondition 검색조건.
    * @param searchKeyword 검색키워드.
    * @return CaseInsensitiveMap 공개게시판 리스트.
    * @throws Exception the exception
    */
    public List selectTopQnaList(String domainId, String customerId, int ipageNo, int rowsPerPage,
            String orderBy, String searchNodeId, String searchCondition, String searchKeyword) throws Exception
    {
    	String channelId = null;
    	return selectTopQnaList(domainId, customerId, channelId, ipageNo, rowsPerPage,
                orderBy, searchNodeId, searchCondition, searchKeyword);
    }
    /**
     * <pre>
     * 공개게시판 리스트를 가져오는 메소드
     * </pre>.
     *
     * @param domainId 도메인ID.
     * @param customerId 고객ID.
     * @param ipageNo 페이지번호.
     * @param rowsPerPage 한페이지 나오는 글 개수.
     * @param orderBy 정렬.
     * @param searchNodeId 검색노드ID.
     * @param searchCondition 검색조건.
     * @param searchKeyword 검색키워드.
     * @return CaseInsensitiveMap 공개게시판 리스트.
     * @throws Exception the exception
     */
     public List selectTopQnaList(String domainId, String customerId, String channelId, int ipageNo, int rowsPerPage,
             String orderBy, String searchNodeId, String searchCondition, String searchKeyword) throws Exception
     {
    	 searchKeyword = searchKeyword.replaceAll("%", "\\\\%");
         searchKeyword = searchKeyword.replaceAll(",", "\\\\,");
         searchKeyword = searchKeyword.replaceAll("_", "\\\\_");
         searchKeyword = "%"+searchKeyword+"%";
         List listRet = null;
         int iStartNum = rowsPerPage * (ipageNo - 1) + 1;
         QnaBoardView obj = new QnaBoardView();
         obj.setQnaDomainId(domainId);
         obj.setCustomerId(customerId);
         obj.setChannelId(channelId);
         obj.setOrderBy(orderBy);
         obj.setRowsPerPage(rowsPerPage);
         obj.setEndNo(ipageNo * rowsPerPage);
         obj.setStartNo(iStartNum);
         obj.setSearchNodeId(searchNodeId);
         obj.setSearchKeyword(searchKeyword);
         obj.setSearchCondition(searchCondition);

         try
         {
             listRet = (List) sqlMap.queryForList("Qna.selectQnaTopList", obj);
         }
         catch (SQLException e)
         {
             logger.error(e.getMessage());
         }
         return listRet;
     }
    /**
    * <pre>
    * QnaID에 해당하는 Qna 정보를 가져오는 메소드
    * </pre>.
    *
    * @param domainId 도메인ID.
    * @param qnaId QnaID.
    *
    * @return QnaID에 해당하는 정보를 반환한다.
    */
    public QnaBoardView selectQnaByQnaId(String domainId, String qnaId)
    {
        QnaBoardView qna = new QnaBoardView();
        QnaBoardView obj = new QnaBoardView();
        obj.setQnaDomainId(domainId);
        obj.setQnaId(qnaId);

        try
        {
            qna = (QnaBoardView) sqlMap.queryForObject("Qna.selectQnaByQnaId", obj);
        }
        catch (SQLException e)
        {
            logger.error(e.getMessage());
        }

        return qna;
    }

    /**
    * <pre>
    * QNA 조회수를 업데이트하는 메소드
    * </pre>.
    *
    * @param qnaId Qna아이디.
    * @return 성공시 true, 실패시 false
    */
    public boolean updateQnaHitCount(String qnaId)
    {
        boolean bSuccess = false;
        int iResult = -1;
        QnaBoardView obj = new QnaBoardView();
        obj.setQnaId(qnaId);
        try
        {
            sqlMap.startTransaction();
            iResult = sqlMap.update("Qna.updateQnaHitCount", obj);
            sqlMap.commitTransaction();
            if (iResult > 0)
            {
                bSuccess = true;
            }
        }
        catch (SQLException e)
        {
            logger.error(e.getMessage());
        }
        finally
        {
            try
            {
                sqlMap.endTransaction();
            }
            catch(SQLException e)
            {
                logger.error(e.getMessage());
            }
        }

        return bSuccess;
    }

    /**
    * <pre>
    * qna_id에 해당하는 contents를 가져오는 메소드
    * </pre>.
    *
    * @param qnaId Qna아이디.
    *
    * @return CaseInsensitiveMap(qna_id에 해당하는 질/답내용 리스트)
    */
    public List selectQnaContents(String qnaId)
    {
        List listRet = null;

        QnaBoardView obj = new QnaBoardView();
        obj.setQnaId(qnaId);

        try
        {
            listRet = (List) sqlMap.queryForList("Qna.selectQnaContentsByQnaId", obj);
        }
        catch (SQLException e)
        {
            logger.error(e.getMessage());
        }
        return listRet;
    }

    /**
    * <pre>
    * qna_id의 이전글을 가져오는 메소드
    * </pre>.
    *
    * @param nodeId 노드ID.
    * @param domainId 도메인ID.
    * @param qnaId Qna아이디.
    * @param channelId 채널ID.
    * @param customerId 고객ID.
    * @param searchCondition 검색조건.
    * @param searchKeyword 검색키워드.
    *
    * @return 이전QNAID.
    *
    * @throws Exception the exception
    */
    public String selectQnaPrevQna(String nodeId, String domainId, String qnaId, String channelId, String customerId,
            String searchCondition, String searchKeyword) throws Exception
    {
        searchKeyword = searchKeyword.replaceAll("%", "\\\\%");
        searchKeyword = searchKeyword.replaceAll(",", "\\\\,");
        searchKeyword = searchKeyword.replaceAll("_", "\\\\_");
        searchKeyword = "%"+searchKeyword+"%";

        String strPrevQnaId = null;
        QnaBoardView obj = new QnaBoardView();
        obj.setSearchNodeId(nodeId);
        obj.setQnaDomainId(domainId);
        obj.setCustomerId(customerId);
        obj.setChannelId(channelId);
        obj.setQnaId(qnaId);
        obj.setSearchKeyword(searchKeyword);
        obj.setSearchCondition(searchCondition);

        try
        {
            strPrevQnaId = (String) sqlMap.queryForObject("Qna.selectQnaPrevQna", obj);
        }
        catch (SQLException e)
        {
            logger.error(e.getMessage());
        }
        return strPrevQnaId;
    }

    /**
    * <pre>
    * qna_id의 다음글을 가져오는 메소드
    * </pre>.
    *
    * @param nodeId 노드ID.
    * @param domainId 도메인ID.
    * @param qnaId Qna아이디.
    * @param channelId 채널ID.
    * @param customerId 고객ID.
    * @param searchCondition 검색조건.
    * @param searchKeyword 검색키워드.
    *
    * @return 다음QNAID.
    *
    * @throws Exception the exception
    */
    public String selectQnaNextQna(String nodeId, String domainId, String qnaId, String channelId, String customerId,
            String searchCondition, String searchKeyword) throws Exception
    {
        searchKeyword = searchKeyword.replaceAll("%", "\\\\%");
        searchKeyword = searchKeyword.replaceAll(",", "\\\\,");
        searchKeyword = searchKeyword.replaceAll("_", "\\\\_");
        searchKeyword = "%"+searchKeyword+"%";

        String strNextQnaId = null;
        QnaBoardView obj = new QnaBoardView();
        obj.setSearchNodeId(nodeId);
        obj.setQnaDomainId(domainId);
        obj.setCustomerId(customerId);
        obj.setChannelId(channelId);
        obj.setQnaId(qnaId);
        obj.setSearchKeyword(searchKeyword);
        obj.setSearchCondition(searchCondition);

        try
        {
            strNextQnaId = (String) sqlMap.queryForObject("Qna.selectQnaNextQna", obj);
        }
        catch (SQLException e)
        {
            logger.error(e.getMessage());
        }
        return strNextQnaId;
    }

    /**
     * 답변채널이 웹게시 일 경우 "답변채널id", "웹게시 여부", "웹게시 메세지"를 추출한다.
     *
     * @param qnaId Qna아이디.
     *
     * @return org.apache.commons.collections.map.CaseInsensitiveMap.<br>
     * channel_id:채널ID.<br>
     * message_use_flag:메세지사용여부.<br>
     * message:메세지.
     */
    public List selectWebBroadInfo(String qnaId)
    {
        List listRet = null;

        try
        {
            listRet = (List) sqlMap.queryForList("Qna.selectWebBroadInfo", qnaId);
        }
        catch (SQLException e)
        {
            logger.error(e.getMessage());
        }
        return listRet;
    }

    /**
    * <pre>
    * qna 내용을 실제 DB에 insert하는 메소드
    * t_qna, t_qna_board, t_qna_process, t_qna_contents 에 각각 입력한다.
    * </pre>
    *
    * @param qna Qna 객체.
    * @param qnaBoard QnaBoard 객체.
    * @param qnaProcess QnaProcess 객체.
    * @param qnaContents QnaContents 객체.
    * @param attach ArrayList 객체.
    *
    * @return QnaID.
    */
    public String insertQna(Qna qna, QnaBoard qnaBoard, QnaProcess qnaProcess, QnaContents qnaContents, ArrayList attach)
    {
        String strQnaId = "";
        try
        {
            strQnaId = selectNextKey();
            
            qna.setQnaId(strQnaId);
            qnaBoard.setQnaId(strQnaId);
            qnaProcess.setQnaId(strQnaId);
            qnaContents.setQnaId(strQnaId);

            String strQuestionContents = qnaContents.getContents();
            String[] arContents = StringUtil.splitContents(strQuestionContents, 1300);

            sqlMap.startTransaction();

            sqlMap.insert("Qna.insertQna", qna);

            sqlMap.insert("Qna.insertQnaBoard", qnaBoard);

            sqlMap.insert("Qna.insertQnaProcess", qnaProcess);

            for (int i = 0; i < arContents.length; i++)
            {
                qnaContents.setContentsSeq(i);
                qnaContents.setContents(arContents[i]);
                sqlMap.insert("Qna.insertQnaContents", qnaContents);
            }

            // 첨부파일 insert
            if (attach != null)
            {
                for(int j=0; j<attach.size(); j++)
                {
                    Attach attachElement = (Attach)attach.get(j);
                    attachElement.setKbId(strQnaId);
                    sqlMap.insert("Attach.insertAttach", attachElement);
                }
            }

            sqlMap.commitTransaction();
        }
        catch(Exception e)
        {
            // QNA등록을 실패할경우 qna_id값을 ""로 넘긴다.
            strQnaId = "";
            logger.error(e.getMessage());
        }
        finally
        {
            try
            {
                sqlMap.endTransaction();
            }
            catch(SQLException e)
            {
                logger.error(e.getMessage());
            }
        }

        return strQnaId;
    }

    /**
    * <pre>
    * 선택값 반전 : select box
    * </pre>.
    *
    * @param s String 객체.
    * @param word String 객체.
    *
    * @return "selected" or ""
    */
    public static String getSelected(String s,String word)
    {
        return s.equals(word) ? "selected" : "";
    }

    /**
    * <pre>
    * 회원아이디를 가지고 총질문개수, 총처리질문개수를 가져오는 메소드
    * </pre>.
    *
    * @param memberId 회원아이디
    * @param domainId 도메인ID.
    *
    * @return org.apache.commons.collections.map.CaseInsensitiveMap.<br>
    * total_count:회원아이디의 질문총갯수.<br>
    * answer_count:회원아이디의 총처리갯수.
    */
    public List selectQnaTotalCountByMemberId(String domainId, String memberId)
    {
        List listRet = null;
        QnaBoardView obj = new QnaBoardView();
        obj.setQnaDomainId(domainId);
        obj.setCustomerId(memberId);
        try
        {
            listRet = (List) sqlMap.queryForList("Qna.selectQnaTotalCountByMemberId", obj);
        }
        catch (SQLException e)
        {
            logger.error(e.getMessage());
        }
        return listRet;
    }

    /**
    * <pre>
    * 고객이 답변이메일을 열었을 때 호출한다.
    * </pre>
    *
    * @param qnaInfo Base64 로 인코딩된 qnaId + "." + processSeq
    * @return 성공시 true, 실패시 false
    */
    public boolean updateQnaReadDate(String qnaInfo)
    {
        try
        {
            String strDecode = new String(Base64.decode(qnaInfo));
            int iIndex = strDecode.indexOf('.');
            if (iIndex == -1)
            {
                return false;
            }

            String strQnaId = strDecode.substring(0, iIndex);
            String strProcessSeq = strDecode.substring(iIndex+1);
            if (strQnaId.length() != 14 || !StringUtil.isNumeric(strProcessSeq))
            {
                return false;
            }

            QnaProcess paramQnaProcess = new QnaProcess();
            paramQnaProcess.setQnaId(strQnaId);
            paramQnaProcess.setProcessSeq(Integer.parseInt(strProcessSeq));

            // 존재하는 지 확인한다.
            QnaProcess qnaProcess = (QnaProcess) sqlMap.queryForObject("Qna.selectQnaProcessByPK", paramQnaProcess);
            if (qnaProcess == null)
            {
                return false;
            }

            // 중간답변,답변완료,추가답변인지 확인한다.
            if ( !("ANTMP".equals(qnaProcess.getType())
                   || "ANEND".equals(qnaProcess.getType())
                   || "ANADD".equals(qnaProcess.getType())) )
            {
                System.out.print(qnaProcess.getType());
                return false;
            }

            // 이미 데이타가 있으면 리턴한다.
            if (StringUtil.isNotBlank(qnaProcess.getReadDate()))
            {
                return false;
            }

            paramQnaProcess.setReadDate(DateUtil.getCurrDateTimeStamp());
            sqlMap.update("Qna.selectQnaProcessReadDate", paramQnaProcess);
        }
        catch (Exception e)
        {
            logger.error(e.getMessage());
            return false;
        }
        return true;
    }

    /**
    * <pre>
    * 고객이 답변이메일을 열었을 때 호출한다.
    * </pre>
    *
    * @param mailInfo 메일정보.
    * @return 성공시 true, 실패시 false
    */
    public boolean updateMailReceiverReadDate(String mailInfo)
    {
        try
        {
            String strDecode = new String(Base64.decode(mailInfo));
            int iIndex = strDecode.indexOf('.');
            if (iIndex == -1)
            {
                return false;
            }

            String strMailId = strDecode.substring(0, iIndex);
            int iReceiverSeq = Integer.parseInt(strDecode.substring(iIndex+1));
            if (strMailId.length() != 14 || !StringUtil.isNumeric(strDecode.substring(iIndex+1)))
            {
                return false;
            }

            MailReceiver paramReceiver = new MailReceiver();
            paramReceiver.setMailId(strMailId);
            paramReceiver.setReceiverSeq(iReceiverSeq);
            paramReceiver.setReadDate(DateUtil.getCurrDateTimeStamp());
            paramReceiver.setUpdatedDate(DateUtil.getCurrDateTimeStamp());

            // 존재하는 지 확인한다.
            MailReceiver mailReceiver = (MailReceiver) sqlMap.queryForObject("Qna.selectMailReceiverByPK", paramReceiver);
            if (mailReceiver == null)
            {
                return false;
            }

            // 이미 데이타가 있으면 리턴한다.
            if (StringUtil.isNotBlank(mailReceiver.getReadDate()))
            {
                return false;
            }

            sqlMap.update("Qna.updateMailReceiverReadDateByPK", paramReceiver);
        }
        catch (Exception e)
        {
            logger.error(e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * 고객 정보를 받아서 업데이트 한다.
     *
     * @param qnaId Qna ID
     * @param customerId 고객 ID
     * @param customerEmail 고객 Email
     * @param customerName 고객 이름
     * @param customerTel 고객 연락처
     * @param customerNo 고객 식별번호
     * @return 적용된 row수
     */
    public int updateCustomerInfo(String qnaId, String customerId, String customerEmail, String customerName, String customerTel, String customerNo)
    {
        int iret = 0;
        try
        {
            Qna qna = new Qna();
            qna.setQnaId(qnaId);
            qna.setCustomerId(customerId);
            qna.setCustomerEmail(customerEmail);
            qna.setCustomerName(customerName);
            qna.setCustomerTel(customerTel);
            qna.setCustomerNo(customerNo);
            sqlMap.startTransaction();
            iret = sqlMap.update("Qna.updateCustomerInfo", qna);
            sqlMap.commitTransaction();
        }
        catch (Exception e)
        {
            logger.error(e.getMessage());
        }
        finally
        {
            try
            {
                sqlMap.endTransaction();
            }
            catch(SQLException e)
            {
                logger.error(e.getMessage());
            }
        }
        return iret;
    }

    /**
     * 주어진 QnA ID 에 해당하는 모든 QnA Process 리스트를 가져온다.
     * @param qnaId Qna ID
     * @return qnaProcess 리스트
     */
    public List selectQnaProcessListByQnaId(String qnaId)
    {
        List lstQnaProcess = null;
        try
        {
            lstQnaProcess = (List) sqlMap.queryForList("Qna.selectQnaProcessByQnaId", qnaId);
        }
        catch (SQLException e)
        {
            logger.error(e.getMessage());
        }
        return lstQnaProcess;
    }
    
    /**
     * t_qna 테이블의 다음 키를 가져온다.
     *
     * @return 다음 키.
     *
     * @throws SQLException the SQL exception
     */
    public String selectNextKey() throws SQLException
    {
        String ret = null;
        try
        {
            sqlMap.startTransaction();
            Map paramMap = new HashMap();
            ret = (String) sqlMap.queryForObject("Qna.selectNextQnaKey", paramMap);
            // 오라클인 경우에는 paramMap에 들어 있다.
            if( ret == null )
                ret = (String) paramMap.get("v_key_id");
            sqlMap.getCurrentConnection().commit();
        }
        catch(Exception e)
        {
            logger.warn(LP.NOTE, "Failed to create Key.", e);
            ret = (String) sqlMap.queryForObject("Qna.selectNextKey");
            
            sqlMap.update("Qna.updateKeySeqByPK", DateUtil.getCurrDateTimeStamp());
        }
        finally
        {
            try
            {
                sqlMap.endTransaction();
            }
            catch(SQLException e)
            {
                logger.warn(e.getMessage());
            }
        }
        return ret;
    }    
}